Skip to content

fix(sysio): preserve epoch batch reward rosters (WIRE-343) - #576

Merged
huangminghuang merged 7 commits into
masterfrom
fix/wire-343-multi-epoch-batch-operator-rewards
Sep 4, 2026
Merged

fix(sysio): preserve epoch batch reward rosters (WIRE-343)#576
huangminghuang merged 7 commits into
masterfrom
fix/wire-343-multi-epoch-batch-operator-rewards

Conversation

@huangminghuang

@huangminghuang huangminghuang commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Record the immutable operator roster used by each batch epoch in batchepochs, so delayed batch payouts use the historical recipients that actually earned each epoch's credits.
  • Pay complete-history batches using credits accumulated across the distinct stored rosters while preserving the existing reward-table ABI.
  • Bound pay_cadence_epochs to 1-10 and each payout to at most 100 recipient credits. With the intended 21-operator roster, the supported maximum cadence is 4 epochs (about 24 minutes at six-minute epochs); raising this conservative execution bound requires separate CPU/KV evidence.
  • Recover from missing roster history without halting emissions: retain the batch emission slice in the sysio treasury and leave the fee bucket in sysio.reserv for the next payable period. Complete but entirely empty roster history likewise preserves sysio.reserv custody instead of stranding the bucket in the treasury. epochlog records history completeness and retained amounts.
  • Retain epochlog history by completed payment rows, expose the completeness/retention audit fields through the generated ABI, and document runtime, deployment, custody, and monitoring invariants.
  • Revalidate stored sysio.system cadence when sysio.epoch::setconfig changes operators_per_epoch, including a diagnostic that identifies the stored system setting.
  • Merge current master and regenerate the conflicting sysio.epoch and sysio.system WASM artifacts from the combined sources.

Validation

  • Exact-content hygiene, CDT SDK freshness, submodule, workflow, configure, full-build, and artifact-copy build gates passed and were promoted to committed head fd9fbd2f9c350f30ba77af5bc7749638b01f4a5c.
  • The direct contract suite passed all 725 test cases; the isolated artifact-copy contracts_unit_test also passed. Focused source and artifact system suites each passed 619 selected cases / 29,536 assertions, including the all-empty custody case and the incomplete-period-to-complete-period fee recovery sequence.
  • The regenerated sysio.epoch and sysio.system WASM files match the combined-source build outputs byte-for-byte.
  • The previous head's canonical local and remote flow-emissions-soak runs passed all 81 phases / 311 steps, including the 1,800-second stability loop. Exact-head CI and flow evidence are being refreshed after the merge.
  • The full ten-file diff and seven-commit list were re-read after the latest review follow-up; the upstream one-epoch-ahead batch-roster publication remains compatible with the immutable roster captured for the epoch that just accrued.

Reviewer notes

  • This system is pre-launch, so backward compatibility with previously serialized epochlog rows is intentionally out of scope.
  • Deploy the sysio.system and sysio.epoch contract updates together during a quiesced window before resuming epoch processing.
  • Configuration remains jointly bounded by operators_per_epoch * pay_cadence_epochs <= 100; update epoch capacity before system cadence when increasing the supported product.
  • Current-head GitHub CI and exact-head flow-emissions-soak are pending after review follow-up fd9fbd2f9c.

Change-Id: Iaa60f6d7cfad4dc0662b5b81b6e8781acf120741
@huangminghuang
huangminghuang requested a review from a team August 20, 2026 00:29
@heifner heifner removed their assignment Aug 20, 2026
@heifner
heifner self-requested a review August 20, 2026 13:29

@heifner heifner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design looks sound — the roster recorded by rcrdbatch is read after the window slide so it matches the epoch/group accrueepoch credits, the KV key is big-endian so batchepochs iterates in ascending epoch order (contiguity walk is valid), the erase(it) loop is safe, and ABI table_id 22503 has no collisions.

5 findings inline: 2 chain-halt risks on the mandatory advance inline path, 1 missing build artifact, 2 minor.

Comment thread contracts/sysio.system/src/emissions.cpp Outdated
Comment thread contracts/sysio.system/src/emissions.cpp Outdated
Comment thread contracts/sysio.system/sysio.system.abi
Comment thread contracts/sysio.system/src/emissions.cpp Outdated
Comment thread contracts/sysio.epoch/src/sysio.epoch.cpp
Change-Id: I0cb745aebe72c6b63c0bc7bbe0af94254b27dd52

@heifner heifner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at 1ab98aff5 (after the artifact refresh). Status of the 2026-08-20 findings, plus one new one.

Resolved

  • sysio.system.abi:2124 — artifact mismatch. 1ab98aff5 adds both sysio.system.wasm and sysio.epoch.wasm, so the source-tree pair is consistent again. One nit for the squash: that commit touches only the two .wasm files with no accompanying source change, which is the shape commit-wasm-only-with-source-change.md bans per-commit. The PR as a whole pairs source with artifacts, so this is history hygiene rather than a provenance gap.

Still open, unchanged at head

  • emissions.cpp:684rcrdbatch's cap throw on the mandatory inline advance path.
  • emissions.cpp:823 — incomplete-history hard abort. One more concrete trigger added in that thread.
  • emissions.cpp:1043 — the clear loop is still outside the accrued_epochs > 0 guard: the guard opens at L1035 and closes at L1039, and batch_history.erase runs unconditionally at L1043.
  • sysio.epoch.cpp:889payepoch's now-unused second parameter is still serialized on every pay epoch.

New

  • emissions.cpp:678 — an O(cadence × roster) deserialize on every advance, used only to produce a count. Inline below.

Comment thread contracts/sysio.system/src/emissions.cpp Outdated
Change-Id: Ic6236e59b9d59eb8727d55228ceaea2d9b8aee86
@huangminghuang
huangminghuang requested a review from heifner August 24, 2026 14:16

@heifner heifner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at 619f5d0a5. All six findings from the previous rounds are fixed — confirmed against the source, so I'm resolving those threads:

Finding Fix
emissions.cpp:684 cap throw → chain halt Counting loop deleted; O(1) contains/erase probe of epoch_index - MAX_PAY_CADENCE_EPOCHS, guarded against the uint32_t underflow
emissions.cpp:823 incomplete history → chain halt check removed; non-halting retain path
period_start_epoch == 0 ? 1 seed Seeds from the earliest recorded roster
emissions.cpp:1043 erase outside the guard Now inside if (accrued_epochs > 0)
sysio.epoch.cpp:889 unused payepoch arg Now sends an empty vector
ABI/wasm mismatch Fixed in 1ab98aff5

The effective_pay_cadence_epochs clamp is a good addition I hadn't asked for. Payout math, roster/epoch attribution, the contiguity triple, big-endian KV ordering, and erase(const_iterator) safety in the clear loop all verified sound.

Four new findings inline. The first one is a refinement of my own earlier suggestion — I proposed "print and retain in treasury" to remove the halt cliff, and retained turns out to mean permanently absorbed, which isn't what I intended.

Comment thread contracts/sysio.system/src/emissions.cpp Outdated
Comment thread contracts/sysio.system/src/emissions.cpp
Comment thread contracts/sysio.epoch/src/sysio.epoch.cpp Outdated
Comment thread contracts/sysio.system/EMISSIONS.md Outdated
Change-Id: I53a5b7164995c9157a9dbe0a0a6e769a5d26cc0a
@huangminghuang
huangminghuang requested a review from heifner August 24, 2026 22:06

@heifner heifner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at dab8091ed. Converging — the previous round's four findings are addressed and only two new ones surfaced, one of which is a residual of finding 1 rather than something new.

Verified this round: the period length is provably <= MAX_PAY_CADENCE_EPOCHS, so rcrdbatch's exact epoch_index - 10 prune holds the table at <= 10 rows; sum(active_epochs) == accrued_epochs by construction, so the two integer divisions partition the pools exactly with no div-by-zero; batch_payout_credits is provably <= 100 for any setter-accepted config; the runtime credit cap is fail-safe (it routes to retention rather than paying some operators and not others); and the reworked epochlog prune is exact.

Two items below, plus a question about the cadence ceiling that I think needs a decision before this merges.

Comment thread contracts/sysio.system/src/emissions.cpp Outdated
Comment thread contracts/sysio.system/include/sysio.system/emissions.hpp
Comment thread contracts/sysio.system/EMISSIONS.md Outdated
Comment thread contracts/sysio.system/src/emissions.cpp
Change-Id: Ifd82421f9204fe64c782a87f1daad096d17c03b5
@huangminghuang
huangminghuang requested a review from heifner August 26, 2026 14:36
Change-Id: I0ee8c3f486a722a3dc72f8914986b2e5b11d0c7b

@heifner heifner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at 5acf5d6c44. The four findings from the previous round are fixed. Since the change since then is the master merge, I checked the merge itself rather than just the source diff:

  • Both conflicted wasms were rebuilt from merged source, not resolved by picking a side: each blob differs from both parents, the merged sysio.epoch.wasm carries master's SOL-378 withhold diagnostic alongside this PR's cadence check, and master's removed delsnapprov is absent from the merged sysio.system.wasm.
  • The merge tree differs from the mechanical auto-merge in exactly those two blobs — no source edits rode along — and every other contract artifact is byte-identical to master.
  • The merged ABI is the exact union: rcrdbatch / batch_epoch / batchepochs / the three epochlog fields added, master's delsnapprov and threshold_pct dropped.
  • No semantic conflict with SOL-378: rcrdbatch still receives the group on duty now while the attestation ships the lookahead index, and the empty-group withhold skips the queueout without returning from advance — so rcrdbatch still pairs with every accrueepoch and this PR's contiguity invariant holds.
  • WIRE-375's symbol refactor is constant-only (same {"WIRE", 9}) and leaves drainrewards untouched, so the fee-deferral path is unaffected.

On the round-4 fixes: the credit-cap trip and the over-long-history break both set batch_history_complete = false before the drain gate, so an over-budget roster no longer sweeps a bucket it cannot distribute; effective_pay_cadence_epochs divides by max(operators_per_epoch, 1); and the reserv side tolerates deferral (add_capped_u64 accrual, get_reserv_rewards_balance clamped to asset::max_amount).

Two low items inline. Worth watching this head's CI specifically: the merge pairs master's regenerated unittests/snapshots/* and deep-mind.log with two freshly rebuilt production wasms, a combination neither side has run.

Comment thread contracts/sysio.system/src/emissions.cpp Outdated
Comment thread contracts/tests/emissions_tests.cpp
Change-Id: I36b05aa02a1db9fba6fa19df0be44cefbfc958ea
@huangminghuang
huangminghuang merged commit 4418407 into master Sep 4, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants